
#include "contactinfo.h"
#include "mainwindow.h"

#include "talkui.h"
#include "ui_mainwindow.h"
#include <QMessageBox>
#include <QHostInfo>
#include <QDateTime>
#include <QDir>
#include <QNetworkInterface>
#include <QTextCodec>
#include <QDebug>
#include<QCloseEvent>
#include<QScreen>
#include<QPixmap>
#include<QClipboard>
#include<QDesktopWidget>
#include <QDesktopServices>
#include <QTimer>
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //    初始化  获取本机ip,mac

    QDir dir;
    sourceHostUserName= dir.home().dirName();
    sourceHostName= QHostInfo::localHostName();
    sourceMac= getHostMacAddress();
    sourceIp=getHostIpAddress(sourceHostName);
    sqlUtil=new SqlUtil();
//    显示时间
    QTime  curtime=QTime::currentTime();
    QString strtm=curtime.toString("hh:mm:ss");
    ui->myLcdNumber->display(strtm);
    QTimer *timer1=new QTimer();
    connect(timer1,&QTimer::timeout,[=](){
               ui->myLcdNumber->display(curtime.currentTime().toString("hh:mm:ss"));
    });
    timer1->start(1000);
    //    设置默认UI样式
    TalkUI::setPushTextButtonQss(ui->talkTabBtn);
    TalkUI::setPushTextButtonQss(ui->talkOptionBtn);
    TalkUI::setPushTextButtonQss(ui->aboutTabBtn);
    TalkUI::setPushTextButtonQss(ui->setTabBtn);
    TalkUI::setPushButtonQss(ui->sendMsgBtn);
    TalkUI::setPushTextButtonQss(ui->emptyBtn);
    contactList = new ContactList();
    TalkUI::setContactListQss(contactList);
    ui->contactListWrap->addWidget(contactList);

    talkMsgList = new TalkMsgList();
    talkMsgList->setViewMode(QListView::ListMode);
    talkMsgList->setFlow(QListView::TopToBottom);
    TalkUI::setTalkMsgListQss(talkMsgList);
    ui->talkMsgListWrap->addWidget(talkMsgList);
    //   默认隐藏会话界面
    ui->talkBoxEmpty->setVisible(true);
    ui->talkBox->setVisible(false);
    //    联系人列表项点击切换时，清空当前会话，获取当前切换到的联系人的消息历史记录，更新到视图
    connect(contactList,&ContactList::contactItemClick,this,[this](ContactInfo *contactInfo){
        if(curContact!=nullptr&&contactInfo->sourceMac==curContact->sourceMac){
            return;
        }

        //        更新当前会话界面的用户信息
        curContact=contactInfo;
        ui->nickName->setText(contactInfo->sourceHostUserName);
        //        清空当前会话
        talkMsgList->clear();
        //       显示会话视图
        ui->talkBoxEmpty->setVisible(false);
        ui->talkBox->setVisible(true);
        //        获取当前切换到的联系人的消息历史记录,更新到视图
        QList<ContactInfo*> *myTalkList=sqlUtil->talkRecordListByContactMac(contactInfo);
        if(myTalkList!=nullptr){

            for(int i=0;i<myTalkList->size();i++){
                ContactInfo  *item=myTalkList->value(i);
                if(item->sourceMac==MainWindow::sourceMac){
                    item->sourceHostUserName=this->sourceHostUserName;
                }else {
                    item->sourceHostUserName=curContact->sourceHostUserName;
                }
                talkMsgList->slotAddMsg(item,item->sourceMac==MainWindow::sourceMac);
            }


        }

    });
    connect(sqlUtil,&SqlUtil::initSuccess,this,[this](){
        //          数据打开成功，加载用户列表
        QList<ContactInfo*> *myContactList=sqlUtil->contactList();
        if(myContactList!=nullptr){
            for(int i=0;i<myContactList->size();i++){
                ContactInfo  *item=myContactList->value(i);
                contactList->slotAddContact(item,item->sourceMac==MainWindow::sourceMac);
            }
        }


    });
    //    打开db前先绑定信号，否则接收不到
    sqlUtil->openDb();


    // 聊天主窗口显示，开始创建套接字通信对象
    mSocket=new QUdpSocket(this);

    // 开始绑定本机端口号2425
    bool isBindPort=mSocket->bind(sourcePort);
    if(isBindPort){
        // 绑定成功
        // 向广播地址发送本机上线通知
        MainWindow::reportOnline();
        // 开始监听收到的消息
        connect(mSocket,&QUdpSocket::readyRead,this,[this](){
            receiveHandle();
        });
    }else {
        //        绑定失败
        QMessageBox::warning(this,"提示","端口绑定失败,请重启软件！");
    }
}



//发送按钮点击事件
void MainWindow::on_sendMsgBtn_clicked()
{

    if(curContact!=nullptr){
        QString sendMsg= ui->msgInput->toPlainText();
        if(sendMsg==""){
            //            QMessageBox::warning(this,"提示","请输入内容");
            return;
        }
        ContactInfo *contactInfo=new ContactInfo;
        QString redayMsg= buildFormatMsg(MsgProtocol::Xfg,MsgTypeCode::SendMsg,sendMsg,contactInfo);

        sendHandle(redayMsg,QHostAddress(curContact->sourceIp));

        ui->msgInput->clear();
        if(curContact->sourceMac!=MainWindow::sourceMac){
            contactInfo->ContactMac=curContact->sourceMac;
            sqlUtil->addMsg(contactInfo);
            talkMsgList->slotAddMsg(contactInfo,contactInfo->sourceMac==MainWindow::sourceMac);
        }

        qDebug()<<"发送了一条消息,接收方："<<curContact->sourceIp;
    }else {
        QMessageBox::warning(this,"提示","请选择联系人");
    }


}

void MainWindow::playNewMsgSound()
{
    QSound::play(":/sound/ring1.wav");
}

//广播上线通知
void MainWindow::reportOnline()
{
    qDebug()<<"---开始广播上线通知---";
    QString redayMsg= buildFormatMsg(MsgProtocol::Xfg,MsgTypeCode::Online);
    sendHandle(redayMsg,QHostAddress::Broadcast);
}

//构建发送的数据包格式
QString MainWindow::buildFormatMsg(MsgProtocol msgProtocol,MsgTypeCode msgTypeCode,QString msg,ContactInfo *contactInfo){
    //    QString destIp="255.255.255.255";   //当前网段广播地址
    QString curTime=QString::number(QDateTime::currentDateTime().toTime_t());
    //数据包前缀格式：version:package#sourceMac#curTime:sourceHostUserName:sourceHostName:msgTypeCode:
    QString prefix="%1:%2:%3:%4:%5:";
    QString readyMsg=prefix.arg(version).arg(package+"#"+sourceMac+"#"+curTime).arg(sourceHostUserName).arg(sourceHostName).arg(msgTypeCode);
    if(contactInfo!=nullptr){
        contactInfo->version=version;
        contactInfo->packageNo=package;
        contactInfo->sourceMac=sourceMac;
        contactInfo->timeStamp=curTime;
        contactInfo->sourceHostUserName=sourceHostUserName;
        contactInfo->sourceHostName=sourceHostName;
        contactInfo->msgTypeCode=msgTypeCode;
        contactInfo->msgPayLoad=msg;
        contactInfo->sourceIp=sourceIp;
    }
    switch (msgTypeCode)
    {

    case MsgTypeCode::Online:{
        readyMsg=readyMsg+"";
        break;
    }
    case MsgTypeCode::AnsOnline:{
        readyMsg=readyMsg+"";
        break;
    }
    case MsgTypeCode::Offline:{
        readyMsg=readyMsg+"";
        break;
    }
    case MsgTypeCode::SendMsg:{
        readyMsg=readyMsg+msg;

        break;
    }
    default:{
        break;
    }

    }
    return readyMsg;
}

//关闭程序事件
void MainWindow::closeEvent(QCloseEvent *event){
    QMessageBox msgBox;
    int ret = msgBox.question(this,"警告","确认退出程序？",QMessageBox::Ok | QMessageBox::Cancel,QMessageBox::Ok);
    if(ret == QMessageBox::Ok){
        //窗口关闭
        //向广播地址发送本机离线通知
        QString redayMsg= buildFormatMsg(MsgProtocol::Xfg,MsgTypeCode::Offline);
        sendHandle(redayMsg,QHostAddress::Broadcast);
        event->accept();
    }else{
        //忽略窗口关闭
        event->ignore();
    }
}
//发送数据处理
void MainWindow::sendHandle(QString readyMsg,QHostAddress addr){
    qDebug()<<"发送："<<readyMsg;
    QTextCodec *tc = QTextCodec::codecForName("GBK");
    mSocket->writeDatagram(tc->fromUnicode(readyMsg),addr,destPort);

}
//接收数据处理
void MainWindow::receiveHandle(){
    char msg[1024]={0};
    QHostAddress ipAddress;  //源ip地址
    mSocket->readDatagram(msg,sizeof msg,&ipAddress);
    QString sourceIp=ipAddress.toString().replace("::ffff:","");
    QTextCodec *tc = QTextCodec::codecForName("GBK");
    QString msgStr= tc->toUnicode(msg);
    if(msgStr.contains("xfg")){
        QStringList msgList=msgStr.split(":");  //版本号:包信息：用户名：主机名：命令编号：附加消息
        qDebug()<<"收到："<<msgList;
        QString version=msgList[0];
        QStringList package=msgList[1].split("#");  //包号#mac#时间戳
        QString packageNo=package[0];
        QString sourceMac=package[1];
        QString timeStamp=package[2];
        QString sourceHostUserName=msgList[2];
        QString sourceHostName=msgList[3];
        QString msgTypeCode=msgList[4];
        QString msgPayLoad=msgList[5];
        ContactInfo *contactInfo=new ContactInfo;
        contactInfo->version=version;
        contactInfo->packageNo=packageNo;
        contactInfo->sourceMac=sourceMac;
        contactInfo->timeStamp=timeStamp;
        contactInfo->sourceHostUserName=sourceHostUserName;
        contactInfo->sourceHostName=sourceHostName;
        contactInfo->msgTypeCode=msgTypeCode;
        contactInfo->msgPayLoad=msgPayLoad;
        contactInfo->sourceIp=sourceIp;
        contactInfo->ContactMac=sourceMac;
        switch (msgTypeCode.toInt()) {
        case MsgTypeCode::Online:{
            //            qDebug()<<"---有新上线好友---"<<sourceIp;
            //            添加到好友列表
            addToContactList(contactInfo);
            //发送响应
            QString redayMsg= buildFormatMsg(MsgProtocol::Xfg,MsgTypeCode::AnsOnline,"");
            sendHandle(redayMsg,QHostAddress(sourceIp));
            break;
        }
        case MsgTypeCode::AnsOnline:{
            addToContactList(contactInfo);
            break;
        }
        case MsgTypeCode::Offline:{
            //            qDebug()<<"---有好友下线---"<<sourceIp;
            break;
        }
        case MsgTypeCode::SendMsg:{
            //            qDebug()<<"---有新消息---"<<sourceIp;
            MainWindow::addMsgHandle(contactInfo);

            break;
        }
            //        case MsgTypeCode::GetPubKey:{

            //            break;
            //        }
            //        case MsgTypeCode::AnsPubKey:{
            //                        QString redayMsg= buildFormatMsg(MsgProtocol::Xfg,MsgTypeCode::AnsPubKey);
            //                        sendHandle(redayMsg,QHostAddress(curContact->sourceIp));
            //            break;
            //        }
        default:{
            break;
        }
        }
    }

}
//获取主机ip地址
QString MainWindow::getHostIpAddress(QString hostName)
{
    QHostInfo hostinfo = QHostInfo::fromName(hostName);
    QString ipAddr="";
    foreach(QHostAddress address,hostinfo.addresses())
    {
        if(address.protocol() == QAbstractSocket::IPv4Protocol)
        {
            ipAddr=address.toString();

        }
    }
    return  ipAddr;
}
//获取主机mac地址
QString MainWindow::getHostMacAddress()
{
    QList<QNetworkInterface> ints = QNetworkInterface::allInterfaces();
    int intsCount = ints.count();
    QString macAddr="";
    for(int i = 0; i < intsCount; i ++)
    {
        QNetworkInterface::InterfaceFlags  intFlags= ints[i].flags();
        if(intFlags.testFlag(QNetworkInterface::IsUp) && intFlags.testFlag(QNetworkInterface::IsRunning) && (!intFlags.testFlag(QNetworkInterface::IsLoopBack)))
        {
            macAddr=ints[i].hardwareAddress();
            break;
        }
    }
    return macAddr.replace(":","");
}
//1添加新用户到数据库，2更新用户列表显示
void MainWindow::addToContactList(ContactInfo *contactInfo){
    //    根据mac地址查询当前新用户是否在数据库中已存在
    if(sqlUtil->contactListByMacAddr(contactInfo)){
        //已存在，更新该用户的信息到数据库

        //更新到视图
        //contactList->slotRefrechContact(contactInfo,contactInfo->sourceMac==MainWindow::sourceMac);
        if(curContact!=nullptr&&contactInfo->sourceMac==curContact->sourceMac){
            //该用户是当前打开的聊天会话的联系人,则同步更新curContact中的数据
            curContact=contactInfo;
        }else{
            //该用户不是当前打开的聊天会话的联系人
        }
    }else{
        //不存在，直接新增用户到数据库
        sqlUtil->addContact(contactInfo);
        //更新到视图
        contactList->slotAddContact(contactInfo,false);
    }
}
//1添加新消息到数据库，2直接追加新消息到聊天界面
void MainWindow::addMsgHandle(ContactInfo *contactInfo){
    //根据mac地址判断当前接收到的新消息的是谁发的

    if(sqlUtil->contactListByMacAddr(contactInfo)){
        // 新消息的发送人在已有的联系人列表中，则直接添加到数据库
        sqlUtil->addMsg(contactInfo);
        if(curContact!=nullptr&&contactInfo->sourceMac==curContact->sourceMac){
            //新消息的发送人是当前打开的聊天会话的联系人,则同步更新消息到聊天会话界面上显示
            talkMsgList->slotAddMsg(contactInfo,contactInfo->sourceMac==MainWindow::sourceMac);
        }else{

            //新消息的发送人不是当前打开的聊天会话的联系人,在新用户头像上显示红点提示,声音提示
            //contactList->showRedDot(contactInfo);
            playNewMsgSound();
        }

    }else {
        // 新消息的发送人在不在联系人列表中,先在数据库添加该新联系人，
        sqlUtil->addContact(contactInfo);


        //然后再将新消息添加到数据库
        sqlUtil->addMsg(contactInfo);

        //然后更新用户列表界面显示，在新用户头像上显示红点提示
        contactList->slotAddContact(contactInfo,false);
        //contactList->showRedDot(contactInfo);
        playNewMsgSound();
    }

}
MainWindow::~MainWindow()
{

    delete ui;
}



//截图
void MainWindow::on_captureScreenBtn_clicked()
{
    QDesktopWidget *desk = QApplication::desktop();
    QScreen *screen = QGuiApplication::primaryScreen();
    QPixmap pixmap = screen->grabWindow(desk->winId());
    //    QClipboard *clipboard = QApplication::clipboard();
    //    clipboard->setPixmap(pixmap);
}
